#pragma once
#include "Business/Business.h"
#include "Business/DealingHistory.h"
#include "Business/CustomerPosition.h"
#include "Business/Leg.h"
#include "StatusMachine/StatusMachine.h"
#include "Business/Dealing.h"
#include "Business/Band.h"
#include "Business/Policy/ClassicBusinessPosition.h"
#include "Business/ArbitrageLegs.h"
#include "Business/ContractMatcher.h"

class Customer;
class Funds;
class MarketStorage;
class QueueContext;
class DealingRepository;
class CancellationRepository;

class CallAuctionBusiness;

namespace CallAuctionBusinessStatusMachine {
	class Event
	{
	public:
		enum TYPE {NONE,MARKET_EVENT,PENDING_MARKET_EVENT, DEALING_EVENT,START_COMMAND, EDIT_COMMAND,CLEAR_COMMAND,MATCH_COMMAND,CANCEL_COMMAND,OPEN_SIGNAL_COMMAND};
		explicit Event(TYPE type = NONE);
		explicit Event(PendingMarket const& pendingMarket);
		explicit Event(Market const& market);
		explicit Event(Dealing const& dealing);
		int GetType() const { return m_type; }
		PendingMarket const& GetPendingMarket() const {return *(PendingMarket*)m_data;}
		Market const& GetMarket() const { return *(Market*)m_data; }
		Dealing const& GetDealing() const { return *(Dealing*)m_data; }

	private:
		int m_type;
		char m_data[1024];
	};

	typedef Status<CallAuctionBusiness,Event> StatusT;
	class StatusBase : public StatusT
	{
	public:
		StatusBase(std::string const& name, CallAuctionBusiness& context):StatusT(name,context){}
	private:
		virtual void DoBefore();
	};
	typedef ConditionBase<CallAuctionBusiness,Event> ConditionT;
	typedef StatusMachine<CallAuctionBusiness,Event> StatusMachineT;


#define DEFINE_CONDITION(condition_name)						\
	class condition_name : public ConditionT					\
	{															\
	public:														\
	explicit condition_name(CallAuctionBusiness& context)	\
	:ConditionT(context){}										\
	virtual ~condition_name() {}								\
	private:													\
	virtual bool DoCheck(Event const& event);					\
	}

	DEFINE_CONDITION(HasChanceCondition);
	DEFINE_CONDITION(NoChanceCondition);
	DEFINE_CONDITION(AllFinishedCondition);
	DEFINE_CONDITION(AllDealedCondition);
	DEFINE_CONDITION(PartialDealedCondition);
	DEFINE_CONDITION(OffsetExcessSuccessAndHaveSamePositionCondition);
	DEFINE_CONDITION(OffsetExcessSuccessAndNoPositionCondition);

	DEFINE_CONDITION(ClearCondition);
	DEFINE_CONDITION(OffsetMarketCondition);
	DEFINE_CONDITION(MinorOffsetOrderedCondition);
	DEFINE_CONDITION(MinorOffsettedCondition);
	DEFINE_CONDITION(MinorOffsetAllCancelledCondition);

	DEFINE_CONDITION(PartialOffsetedCondition);
	DEFINE_CONDITION(AllOffsetedCondition);
	DEFINE_CONDITION(StartCondition);
	DEFINE_CONDITION(EditCondition);
	DEFINE_CONDITION(CancelCondition);
#undef DEFINE_CONDITION

#define DEFINE_STATUS(class_name,name)					\
	class class_name : public StatusBase					\
	{														\
	public:													\
	explicit class_name(CallAuctionBusiness& context)		\
	:StatusBase(name,context){}							\
	virtual ~class_name(){}								\
	private:											\
	virtual void DoExecute(Event const& event);			\
	}

	DEFINE_STATUS(StartStatus,"start");
	DEFINE_STATUS(SentStatus,"sent");
	DEFINE_STATUS(CancelSentStatus,"cancel sent");
	DEFINE_STATUS(OpenedStatus,"opened");
	DEFINE_STATUS(OffsetExcessStatus,"offset excess sent");
	DEFINE_STATUS(OffsetSentStatus,"offset sent");
	DEFINE_STATUS(StopSentStatus,"stop sent");

	DEFINE_STATUS(WaitToClearStatus,"wait to clear");
	DEFINE_STATUS(MinorOffsetSentStatus,"minor offset sent");
	DEFINE_STATUS(MinorOffsetCancelSentStatus,"minor offset ordered");
	DEFINE_STATUS(MajorOffsetSentStatus,"major offset sent");

	DEFINE_STATUS(EndStatus,"end");
	DEFINE_STATUS(EditableStatus,"editable");
#undef DEFINE_STATUS
}

class Dealing;
class Cancellation;
class TimeoutNotifier;

class CallAuctionArgument
{
public:
	CallAuctionArgument(ArbitrageContracts const& contracts, int maxQuantity,
		Band const& bearish,Band const& bullish, int majorPrePrice, int minorPrePrice, 
		bool useLimitPrice, double majorLimitPercent, double minorLimitPercent)
		:m_contracts(contracts),m_maxQuantity(maxQuantity),m_bearish(bearish),m_bullish(bullish)
		,m_majorPrePrice(majorPrePrice),m_minorPrePrice(minorPrePrice),m_useLimitPrice(useLimitPrice),
		m_majorLimitPercent(majorLimitPercent),m_minorLimitPercent(minorLimitPercent)
	{
	}
	ArbitrageContracts const& GetContracts() const { return m_contracts; }
	int GetMaxQuantity() const { return m_maxQuantity; }
	Band const& GetBearish() const { return m_bearish; }
	Band const& GetBullish() const { return m_bullish; }
	int GetMajorPrePrice() const { return m_majorPrePrice; }
	int GetMinorPrePrice() const { return m_minorPrePrice; }

	bool UseLimitPrice() const { return m_useLimitPrice; }
	double GetMajorLimitPercent() const { return m_majorLimitPercent; }
	double GetMinorLimitPercent() const { return m_minorLimitPercent; }

	int GetFartherPrePrice() const 
	{ 
		if (m_contracts.IsMajorEqualFarther())
		{
			return m_majorPrePrice; 
		}
		else
		{
			return m_minorPrePrice;
		}
	}
	int GetNearbyPrePrice() const 
	{ 
		if (m_contracts.IsMajorEqualFarther())
		{
			return m_minorPrePrice; 
		}
		else
		{
			return m_majorPrePrice;
		}
	}

	void UpdateBand(CallAuctionArgument const& other)
	{
		m_bearish = other.GetBearish();
		m_bullish = other.GetBullish();
	}
private:
	ArbitrageContracts m_contracts;
	int m_maxQuantity;
	Band m_bearish;
	Band m_bullish;
	int m_majorPrePrice;
	int m_minorPrePrice;
	bool m_useLimitPrice;
	double m_majorLimitPercent;
	double m_minorLimitPercent;
};

class CallAuctionBusinessSnapshot 
{
public:
	CallAuctionBusinessSnapshot(char const* status,int minorDirection,
		int majorQuantity,int minorQuantity,double balance,double profit)
		:m_status(status),m_minorDirection(minorDirection),
		m_majorQuantity(majorQuantity),m_minorQuantity(minorQuantity),
		m_balance(balance),m_profit(profit)
	{
	}
	char const* GetStatus() const {return m_status;}
	int GetMinorDirection() const {return m_minorDirection;}
	int GetMinorQuantity() const {return m_minorQuantity;}
	int GetMajorQuantity() const {return m_majorQuantity;}
	double GetBalance() const {return m_balance;}
	double GetProfit() const {return m_profit;}

	bool operator==(CallAuctionBusinessSnapshot const& other) const
	{
		return m_status == other.m_status && m_minorDirection == other.m_minorDirection &&
			m_minorQuantity == other.m_minorQuantity  && m_balance == other.m_balance && m_profit == other.m_profit;
	}
	bool operator!=(CallAuctionBusinessSnapshot const& other) const
	{
		return !operator==(other);
	}
private:
	char const * m_status;
	int m_minorDirection;
	int m_majorQuantity;
	int m_minorQuantity;
	double m_balance;
	double m_profit;
};

struct CalculateResult
{
	int quantity;
	int fartherOrderPrice;
	int nearbyOrderPrice;
	int fartherDealPrice;
	int nearbyDealPrice;
	double profit;
};
class CallAuctionCalculater
{
public:
	CallAuctionCalculater(ContractMatcheres& contractMatchers,CallAuctionArgument const& argument,int minPriceUnit)
		:m_argument(argument),
		m_fartherMatcher(contractMatchers.AddMatcher(argument.GetContracts().GetFarther(),minPriceUnit)),
		m_nearbyMatcher(contractMatchers.AddMatcher(argument.GetContracts().GetNearby(),minPriceUnit))
	{
	}

	void Update(PendingMarket const& pendingMarket);
	void Add(PendingMarket const& pendingMarket);
	void Match();
	void GenerateItems();
	int GetFartherMatchPrice() const { return m_fartherMatchPrice;}
	int GetNearbyMatchPrice() const {return m_nearbyMatchPrice;}
	bool HasNoneMatch() const;
	int GetBalance() const;

	void LogFartherMatchItems() {m_fartherMatcher.LogMatchItems();}
	void LogNearbyMatchItems() {m_nearbyMatcher.LogMatchItems();}

	CalculateResult CalcBearish(double available,MarketStorage const& storage);
	CalculateResult CalcBullish(double available,MarketStorage const& storage);

	double GetFreezeAmount(MarketStorage const& storage) const;
private:
	CallAuctionArgument const& m_argument;
	ContractMatcher& m_fartherMatcher;
	ContractMatcher& m_nearbyMatcher;
	int m_fartherMatchPrice;
	int m_nearbyMatchPrice;
};

class CallAuctionBusiness : public AutoUpdateUIBusiness<CallAuctionBusiness>
{
public:
	typedef CallAuctionArgument Arguemnt;
	typedef CallAuctionBusinessSnapshot Snapshot;
public:

	CallAuctionBusiness(Customer& customer,
		CallAuctionArgument const& argument,
		MarketStorage& marketStorage,
		QueueContext& queueContext, 
		DealingRepository& dealingRepository,
		CancellationRepository& cancellationRepository,
		TimeoutNotifier& timeoutNotifier,
		ContractMatcheres& contractMatchers);

	virtual ~CallAuctionBusiness();

	CallAuctionArgument const& GetArgument() const { return m_argument; }
	int GetMajor() const { return m_argument.GetContracts().GetMajor(); }
	int GetMinor() const { return m_argument.GetContracts().GetMinor(); }
	char const* GetMajorCode() const;
	char const* GetMinorCode() const;
	char const* GetFartherCode() const;
	char const* GetNearbyCode() const;
	ClassicBusinessPosition const& GetPositions() const { return m_positions; }
	bool IsEditable() const;
	bool IsNoChance(PendingMarket const& pendingMarket);

 	CallAuctionBusinessSnapshot GetSnapshot();
	void UpdateUI(CallAuctionBusinessSnapshot const& snapshot);

	void Init();
	
	bool HasChance();

	void LogMatchItems();
	void Open();
	void Cancel();

	bool CanCancel(Dealing const* dealing) const;
	void OffsetExcess();
	void OffsetAllByLimitPrice();

	void OffsetMinor();
	void CancelMinorOffset();
	void OffsetMajorByLimitPrice();

	bool CanOffset() const;
	bool IsAllFinished() const;

	bool HasCanCancelDealing() const
	{
		return CanCancel(m_fartherDealing) || CanCancel(m_nearbyDealing);
	}

	bool IsNearbyFinished() const;
	bool IsFartherFinished() const;
	bool IsAllDealed() const;
	bool HasSamePosition() const;
	bool IsZero() const;
private:

	virtual void DoOnInit();
	virtual void DoOnMarket(Market const& market);
	virtual void DoOnPendingMarket(PendingMarket const& pendingMarket);;
	virtual void DoOnDealing(Dealing const& dealing);

	virtual void DoOnTimeout(RequestTimeout const& requestTimeout);
	virtual void DoOnTrade(Trade const& trade);
	virtual void DoOnCommand(Command const& command);
	virtual void DoOnExchangeStatus(int exchangeStatus);

	bool IsFartherAllCanceled() const;
	bool IsNearbyAllCanceled() const;

	bool IsFartherAllDealed() const;
	bool IsNearbyAllDealed() const;

	bool OpenBearish(double openBalance);
	bool OpenBullish(double openBalance);
	bool CalcBearish();

	void SetOpenQuantityAndPrice(CalculateResult& result, ArbitrageLegs const& legs);
	bool CalcBullish();

	void UpdateArgument(CallAuctionArgument const& argument);
	ArbitrageLegs* GetCurrentLegs() const { return m_currentLegs;}
	Order CreateOrder(Leg const& leg,double price, int quantity);
	Dealing& PushOrder(Order const& order);
	Cancellation& PushCancellation(Cancellation const& cancellation);

	CallAuctionArgument m_argument;
	MarketStorage const& m_marketStorage;
	QueueContext& m_queueContext;
	DealingRepository& m_dealingRepository;
	CancellationRepository& m_cancellationRepository;
	TimeoutNotifier& m_timeoutNotifier;
	CallAuctionBusinessStatusMachine::StatusMachineT* m_machine;
	ArbitrageLegs m_bearishLegs;
	ArbitrageLegs m_bullishLegs;
	ClassicBusinessPosition m_positions;

	ArbitrageLegs* m_currentLegs;

	int m_fartherOpenPrice;
	int m_nearbyOpenPrice;
	int m_quantity;

	Dealing const* m_fartherDealing;
	Dealing const* m_nearbyDealing;

	CallAuctionCalculater m_calculater;

	DealingHistory m_minorOffsetDealingHistory;
};
